﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking;
using Zove.DesignTime;
using Zove.Runtime;
using System.Security.AccessControl;
using Zove.Runtime.Core;

namespace Zove.Desktop {
    public partial class SolutionWindow : DockContent, IDesktopView {
        private const int IMAGE_FOLDER = 0;

        private const int IMAGE_FOLDEROPENED = 1;

        private const int IMAGE_MODEL = 2;

        private const int IMAGE_PROGRAM = 3;

        private const int IMAGE_QUERY = 4;

        private TreeNode root = null;

        private static SolutionWindow instance = null;

        private AutoCompleteStringCollection acsc = null;

        private Dictionary<string, string> files = null;

        public Dictionary<string, ZoomClass> Classes {
            get;
            set;
        }

        public Dictionary<string, ZoomClass> ZoomClasses {
            get;
            set;
        }

        public static SolutionWindow Instance {
            get {
                if (instance == null) {
                    instance = new SolutionWindow(DesktopUtils.ModelPool.Split(';')[0]);
                }

                return instance;
            }
        }

        public ZoomClass GetZoomClass(string className) {
            if (this.ZoomClasses.Keys.Contains(className)) {
                return this.ZoomClasses[className];
            }

            ZoomClass c = this.ObjectCache(className);

            ZoomClass zc = new ZoomClass();
            zc.Name = c.Name;

            if (c.BaseClasses.Count > 0) {

            }

            foreach (ZoomVariable v in c.Variables) {
                if (v.Type != "factor") {
                    ZoomClass instance = this.GetZoomClass(v.Type);
                    //zc.Instances.Add(instance);
                }
            }
            this.ZoomClasses[className] = zc;

            return zc;
        }

        public SolutionWindow(string path) {
            InitializeComponent();
            this.path = path;
            DirectoryInfo di = new DirectoryInfo(this.path);
            base.Text = di.Name + " - Workspace";

            this.files = new Dictionary<string, string>();
            this.acsc = new AutoCompleteStringCollection();
            this.Classes = new Dictionary<string, ZoomClass>();
            this.ZoomClasses = new Dictionary<string, ZoomClass>();
            this.RuntimeModelCollection
                = new Dictionary<string, RuntimeModel>();

            ImageList list = new ImageList();
            list.Images.Add(Properties.Resources.vm_folder);
            list.Images.Add(Properties.Resources.vm_folder_open);
            list.Images.Add(Properties.Resources.DrsRuleVmOk);
            list.Images.Add(Properties.Resources.host);
            list.Images.Add(Properties.Resources.resourcePool);

            this.tvModels.ImageList = list;
            this.tvModels.ImageIndex = 1;

            this.tvModels.DoubleClick += new EventHandler(Pick);
            this.tvModels.KeyUp += new KeyEventHandler(EnterIsPressed);
            this.tvModels.AfterLabelEdit += new NodeLabelEditEventHandler(tvModels_AfterLabelEdit);

            this.UpdateView();
        }

        public void UpdateView() {
            this.tvModels.Nodes.Clear();

            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted
                += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);

            this.pictureBox1.Visible = true;
            bw.RunWorkerAsync();
        }

        public void bw_DoWork(object sender, DoWorkEventArgs args) {
            //DisplayWait(true);
            this.acsc = new AutoCompleteStringCollection();
            this.files = new Dictionary<string, string>();

            this.root = LoadModels();
            this.root.Text = "Workspace";
        }

        public void bw_RunWorkerCompleted(
            object sender, RunWorkerCompletedEventArgs e) {
            this.pictureBox1.Visible = true;
            this.tvModels.Nodes.Add(root);
            this.tvModels.Refresh();

            this.tbFile.AutoCompleteCustomSource = this.acsc;
        }

        public void bw_ProgressChanged(
            object sender, ProgressChangedEventArgs e) {

        }

        public void EnterIsPressed(object sender, KeyEventArgs e) {
            if (e.KeyCode == Keys.Enter) {
                Pick(sender, null);
            }
        }

        public void Pick(object source, EventArgs e) {
            try {
                if (this.tvModels.SelectedNode != null) {
                    object tag = this.tvModels.SelectedNode.Tag;
                    string fileName = this.tvModels.SelectedNode.Name;
                    if (tag == null) {
                        return;
                    }

                    if (tag.ToString() == "Model") {
                        DesktopFormContext.Context.Main.OpenEditWindow(
                            fileName);
                    } else if (tag.ToString() == "Program") {
                        DesktopFormContext.Context.Main.OpenProgrammingWindow(
                            fileName);
                    } else if (tag.ToString() == "Query") {
                        DesktopFormContext.Context.Main.OpenQueryWindow(
                            fileName);
                    }
                }
            } catch (Exception ex) {
                MessageBox.Show(ex.Message);
            }
        }

        public Dictionary<string, RuntimeModel> RuntimeModelCollection {
            get;
            set;
        }

        private string path;

        public TreeNode LoadModels() {
            TreeNode root = new TreeNode();
            DirectoryInfo d = new DirectoryInfo(this.path);
            TreeNode node = AddFolderNode(d);

            root.Nodes.Add(node);
            root.ContextMenuStrip = this.cmsNamespace;

            return root;
        }


        public static bool IsVisibleItem(string ext) {
            string[] m = DesktopUtils.Extensions.Split(';');
            foreach (string n in m) {
                if (n == ext) {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        public TreeNode AddFolderNode(DirectoryInfo d) {
            TreeNode node = new TreeNode();
            node.Name = d.FullName;
            node.Text = d.Name;
            node.Tag = d;
            node.ImageIndex = IMAGE_FOLDER;
            node.SelectedImageIndex = IMAGE_FOLDEROPENED;
            node.ContextMenuStrip = this.cmsNamespace;

            foreach (DirectoryInfo di in d.GetDirectories()) {
                // todo: add exclude paths
                if (di.Name == ".svn") {
                    continue;
                }

                TreeNode n = AddFolderNode(di);
                node.Nodes.Add(n);
            }

            foreach (FileInfo fi in d.GetFiles()) {
                try {
                    if (!IsVisibleItem(fi.Extension)) {
                        continue;
                    }

                    this.acsc.Add(fi.Name);
                    this.files.Add(fi.Name, fi.FullName);

                    TreeNode n = null;
                    switch (fi.Extension) {
                        case ".fpz":
                            n = AddProgramNode(fi);
                            break;
                        case ".fp":
                            n = AddProgramNode(fi);
                            break;
                        case ".zql":
                            n = AddQueryNode(fi);
                            break;
                        case ".zoom":
                            n = AddClassNode(fi);
                            break;
                        default:
                            break;
                    }
                    node.Nodes.Add(n);
                } catch (Exception ex) {

                }
            }

            return node;
        }

        private TreeNode AddQueryNode(FileInfo fi) {
            TreeNode n = new TreeNode();

            n.Tag = "Query";
            n.Text = fi.Name;
            n.Name = fi.FullName;
            n.ImageIndex = IMAGE_QUERY;
            n.SelectedImageIndex = IMAGE_QUERY;
            n.ContextMenuStrip = this.cmsProgram;

            return n;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fi"></param>
        /// <returns></returns>
        public TreeNode AddProgramNode(FileInfo fi) {
            TreeNode n = new TreeNode();

            n.Tag = "Program";
            n.Text = fi.Name;
            n.Name = fi.FullName;
            n.ImageIndex = IMAGE_PROGRAM;
            n.SelectedImageIndex = IMAGE_PROGRAM;
            n.ContextMenuStrip = this.cmsProgram;

            return n;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fi"></param>
        /// <returns></returns>
        public TreeNode AddClassNode(FileInfo fi) {
            string className = fi.Name.Split('.')[0];
            //ZoomClass c = ObjectCache(className);

            TreeNode n = new TreeNode();
            n.Tag = "Model";
            n.Name = fi.FullName;
            n.Text = fi.Name;
            n.ImageIndex = IMAGE_MODEL;
            n.SelectedImageIndex = IMAGE_MODEL;
            n.ContextMenuStrip = this.cmsProgram;
            //BindObjectToTree(c, n);

            return n;
        }

        public void BindObjectToTree(ZoomClass c, TreeNode root) {
            TreeNode n = null;

            Console.WriteLine(c.Name);
            if (c.BaseClasses.Count > 0) {
                foreach (string b in c.BaseClasses) {
                    n = new TreeNode();
                    n.Name = b;
                    n.Tag = "Model";
                    n.Text = "base: " + b;
                    n.ImageKey = "treeviewBaseNode";
                    n.SelectedImageKey = "treeviewBaseNode";
                    //ZoomClass x = this.ObjectCache(b);
                    //n.Tag = x;
                    //this.BindObjectToTree(x, n);

                    root.Nodes.Add(n);
                }
            }

            foreach (ZoomVariable v in c.Variables) {
                n = new TreeNode();
                n.Name = v.Name;
                n.Text = v.Name;
                n.ImageKey = "treeviewVariableNode";
                n.Tag = v;
                root.Nodes.Add(n);

                if (v.Type != "factor") {
                    n.Text = v.Name + ":" + v.Type;
                    //ZoomClass x = this.ObjectCache(v.Type);
                    //n.Tag = x;

                    //this.BindObjectToTree(x, n);
                }
            }
        }

        public ZoomClass ObjectCache(string className) {
            DefaultClassFinder finder = new DefaultClassFinder();
            DefaultClassLoader loader = new DefaultClassLoader();
            loader.Finder = finder;

            if (this.Classes.ContainsKey(className)) {
                return this.Classes[className];
            }

            ZoomClass c = null;
            try {
                c = loader.LoadByClassName(className);
            } catch (Exception ex) {
                Console.WriteLine(ex.Message);
            } finally {
                this.Classes[className] = c;
            }

            return c;
        }

        private void openParentFolderWithWindowsToolStripMenuItem_Click(object sender, EventArgs e) {
            DirectoryInfo di
                = (DirectoryInfo)this.tvModels.SelectedNode.Tag;

            System.Diagnostics.Process p = new Process();

            p.StartInfo.FileName = "explorer";
            p.StartInfo.Arguments = di.FullName;
            p.Start();
        }

        private void editToolStripMenuItem1_Click(
            object sender, EventArgs e) {
            EditingForm f = new EditingForm(
                this.tvModels.SelectedNode.Name);

            f.MdiParent = this.MdiParent;
            f.Show();
        }

        private void runToolStripMenuItem_Click(
            object sender, EventArgs e) {
            RunWindow rw = new RunWindow(
                this.tvModels.SelectedNode.Name);

            rw.MdiParent = this.MdiParent;
            rw.Show(this.DockPanel);
        }

        private void queryToolStripMenuItem1_Click(object sender, EventArgs e) {
            QueryWindow qw = new QueryWindow();

            qw.Source = string.Format(
                "select * from {0};",
                this.tvModels.SelectedNode.Name);
            qw.MdiParent = this.MdiParent;
            qw.Show();
        }

        private void deleteToolStripMenuItem_Click(object sender, EventArgs e) {
            if (MessageBox.Show(
                string.Format(
                "Model {0} is going to be deleted, confirm?",
                this.tvModels.SelectedNode.Text),
                "Delete", MessageBoxButtons.OKCancel
                ) == DialogResult.OK) {
                Delete(this.tvModels.SelectedNode);
            }
        }

        public static void Delete(TreeNode t) {
            if (MessageBox.Show("Delete file " + t.Text + "?", "Delete", MessageBoxButtons.OKCancel) == DialogResult.OK) {
                if (File.Exists(t.Name)) {
                    File.Delete(t.Name);
                }
                t.Remove();
            }
        }

        private void renameToolStripMenuItem1_Click(object sender, EventArgs e) {
            InputDialog i = new InputDialog();

            i.ShowDialog();
        }

        private void runToolStripMenuItem1_Click(
            object sender, EventArgs e) {
            TreeNode node = this.tvModels.SelectedNode;
            FileInfo fi = new FileInfo(node.Name);
            switch (fi.Extension) {
                case ".zql":
                    DesktopFormContext.Context.Main.OpenQueryWindow(node.Name);
                    break;
                case ".zoom":
                    DesktopFormContext.Context.Main.OpenEditWindow(node.Name);
                    break;
                case ".fpz":
                    DesktopFormContext.Context.Main.OpenProgrammingWindow(node.Name);
                    break;
                default:
                    break;
            }
        }

        private void runToolStripMenuItem2_Click(object sender, EventArgs e) {
            TreeNode node = this.tvModels.SelectedNode;
            FileInfo fi = new FileInfo(node.Name);
            switch (fi.Extension) {
                case ".zql":
                    QueryWindow qw = DesktopFormContext.Context.Main.OpenQueryWindow(
                        node.Name);
                    qw.Run();
                    break;
                case ".zoom":
                    string className = node.Text.Split('.')[0];
                    DesktopFormContext.Context.Main.OpenRunWindow(
                        className);
                    break;
                case ".fpz":
                    ProgrammingEditor pe = new ProgrammingEditor(node.Name);

                    pe.Show(DesktopFormContext.Context.Main.DockPanel);
                    pe.DockState = DockState.DockRight;
                    break;
                default:
                    break;
            }
        }

        private void propertiesToolStripMenuItem1_Click(object sender, EventArgs e) {
            PropertiesWindow pw = new PropertiesWindow(
                this.tvModels.SelectedNode.Name);

            pw.Show(this.DockPanel);
            pw.DockState = DockState.DockLeft;
        }

        private void deleteToolStripMenuItem1_Click(object sender, EventArgs e) {
            Delete(this.tvModels.SelectedNode);
        }

        public void Open() {
            if (!this.files.ContainsKey(this.tbFile.Text)) {
                return;
            }

            string fullName = this.files[this.tbFile.Text];
            if (fullName.EndsWith(".fpz")) {
                DesktopFormContext.Context.Main.OpenProgrammingWindow(
                    fullName);
            } else if (fullName.EndsWith(".zql")) {
                DesktopFormContext.Context.Main.OpenQueryWindow(
                    fullName);
            } else if (fullName.EndsWith(".zoom")) {
                DesktopFormContext.Context.Main.OpenEditWindow(
                    fullName);
            } else {
            }
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e) {
            if (MessageBox.Show("Delete folder " + this.tvModels.SelectedNode.Text + "?", "", MessageBoxButtons.YesNo) == DialogResult.Yes) {
                if (Directory.Exists(
                    this.tvModels.SelectedNode.Name)) {
                    Directory.Delete(this.tvModels.SelectedNode.Name);
                }
                this.tvModels.SelectedNode.Remove();
            }
        }

        private void modelToolStripMenuItem_Click(object sender, EventArgs e) {
            string fileName = DesktopFormContext.Context.Main.AddModelDialog(
                this.tvModels.SelectedNode.Name);
            if (!string.IsNullOrEmpty(fileName)) {
                FileInfo fi = new FileInfo(fileName);
                TreeNode n = AddClassNode(fi);
                this.tvModels.SelectedNode.Nodes.Add(n);
                this.tvModels.SelectedNode.Expand();
            }
        }

        private void editToolStripMenuItem_Click(object sender, EventArgs e) {
            Process p = new Process();

            p.StartInfo.Arguments = this.tvModels.SelectedNode.Name;
            p.StartInfo.FileName = "explorer";

            p.Start();
        }

        private void programToolStripMenuItem_Click(object sender, EventArgs e) {
            string fileName
                = DesktopFormContext.Context.Main.AddProgrammingDialog(
                this.tvModels.SelectedNode.Name, DialogType.Program);

            if (!string.IsNullOrEmpty(fileName)) {
                FileInfo fi = new FileInfo(fileName);
                TreeNode n = this.AddProgramNode(fi);

                this.tvModels.SelectedNode.Nodes.Add(n);
                this.tvModels.SelectedNode.Expand();
            }
        }

        private void queryToolStripMenuItem1_Click_1(object sender, EventArgs e) {
            string fileName = "New Query.zql";
            if (!string.IsNullOrEmpty(fileName)) {
                FileInfo fi = new FileInfo(fileName);
                TreeNode n = this.AddQueryNode(fi);

                this.tvModels.SelectedNode.Nodes.Add(n);
                this.tvModels.SelectedNode.Expand();
            }
        }

        private void btnRefresh_Click(object sender, EventArgs e) {
            UpdateView();
        }

        private void btnOpen_Click(object sender, EventArgs e) {
            Open();
        }

        private void toolStripButton3_Click(object sender, EventArgs e) {
            UpdateView();
        }

        private void xMLToolStripMenuItem_Click(object sender, EventArgs e) {
            string fileName
                = DesktopFormContext.Context.Main.AddProgrammingDialog(
                this.tvModels.SelectedNode.Name, DialogType.Text);

            if (!string.IsNullOrEmpty(fileName)) {
                FileInfo fi = new FileInfo(fileName);
                TreeNode n = this.AddProgramNode(fi);

                this.tvModels.SelectedNode.Nodes.Add(n);
                this.tvModels.SelectedNode.Expand();
            }
        }

        private void textToolStripMenuItem_Click(object sender, EventArgs e) {
            string fileName
                = DesktopFormContext.Context.Main.AddProgrammingDialog(
                this.tvModels.SelectedNode.Name, DialogType.Text);

            if (!string.IsNullOrEmpty(fileName)) {
                FileInfo fi = new FileInfo(fileName);
                TreeNode n = this.AddProgramNode(fi);
                this.tvModels.SelectedNode.Nodes.Add(n);
                this.tvModels.SelectedNode.Expand();
            }
        }

        private void ShowAddFileDialog(DialogType type) {
            string fileName
                = DesktopFormContext.Context.Main.AddProgrammingDialog(
                this.tvModels.SelectedNode.Name, type);
            if (!string.IsNullOrEmpty(fileName)) {
                FileInfo fi = new FileInfo(fileName);
                TreeNode n = this.tvModels.SelectedNode.Nodes.Add(fi.FullName, fi.Name);
                this.tvModels.SelectedNode.Expand();
            }
        }

        /// <summary>
        /// Add a new folder
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void itemNewFolder_Click(object sender, EventArgs e) {
            string parentName = this.tvModels.SelectedNode.Name;
            TreeNode folder = this.tvModels.SelectedNode.Nodes.Add(
                parentName + "\\New Folder");
            folder.Text = "New Folder";
            folder.Name = parentName + "\\New Folder";
            Directory.CreateDirectory(folder.Name);

            this.tvModels.SelectedNode.Expand();
            folder.ImageIndex = IMAGE_FOLDER;
            folder.SelectedImageIndex = IMAGE_FOLDEROPENED;
            folder.ContextMenuStrip = this.cmsNamespace;
            folder.BeginEdit();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tvModels_AfterLabelEdit(object sender, NodeLabelEditEventArgs e) {
            string oldName = e.Node.Name;
            string newName = e.Node.Parent.Name + "\\" + e.Label;
            if (e.Node.ImageIndex == IMAGE_FOLDER) {
                if (!Directory.Exists(oldName)) {
                    if (MessageBox.Show("The folder was already deleted in the file system, do you wish to remove it from the workspace?", "Remove", MessageBoxButtons.OKCancel) == DialogResult.OK) {
                        e.Node.Remove();
                    }
                } else {
                    if (oldName.ToLower().Equals(newName.ToLower())) {
                        e.CancelEdit = true;
                    } else {
                        Directory.Move(oldName, newName);
                    }
                }
            } else {
                if (!File.Exists(oldName)) {
                    if (MessageBox.Show("The file " + oldName + " was already deleted in the file system, do you wish to remove it from the workspace?", "Remove", MessageBoxButtons.OKCancel) == DialogResult.OK) {
                        e.Node.Remove();
                    }
                } else {
                    if (oldName.ToLower() == newName.ToLower()) {
                        e.CancelEdit = true;
                    } else {
                        File.Move(oldName, newName);
                    }
                }
            }

            e.Node.Name = newName;

            // if the file was opened in workspace
            foreach (Form form in DesktopFormContext.Context.Main.MdiChildren) {
                if (form.Text == oldName) {
                    form.Text = newName;
                    break;
                }
            }
        }

        private void propertiesToolStripMenuItem_Click_1(object sender, EventArgs e) {
            if (PropertiesWindow.PropertiesView == null) {
                PropertiesWindow.PropertiesView = new PropertiesWindow();
                DesktopFormContext.Context.Main.ShowWindow(PropertiesWindow.PropertiesView);
            }

            PropertiesWindow.PropertiesView.BringToFront();
        }

        #region IDesktopForm Members

        public void Run() {

        }

        public new void Validate() {
            throw new NotImplementedException();
        }

        public void Stop() {
            throw new NotImplementedException();
        }

        public DigitalRune.Windows.TextEditor.TextEditorControl GetTextEditorControl() {
            throw new NotImplementedException();
        }

        public string GetFileName() {
            throw new NotImplementedException();
        }

        public string GetFileExtension() {
            throw new NotImplementedException();
        }

        public void Save(string fileName) {
            throw new NotImplementedException();
        }

        public string GetFileFilter() {
            throw new NotImplementedException();
        }

        public string GetColourScheme() {
            throw new NotImplementedException();
        }

        public void RunInBackground() {
            throw new NotImplementedException();
        }

        #endregion

        #region IDesktopForm Members


        public void Debug() {
            throw new NotImplementedException();
        }

        public void Resume() {
            throw new NotImplementedException();
        }

        public void Restart() {
            throw new NotImplementedException();
        }

        public double Profile() {
            throw new NotImplementedException();
        }

        #endregion
    }
}
